<?php
namespace Action;
use HY\Action;
!defined('HY_PATH') && exit('HY_PATH not defined.');
class Task2 extends HYBBS {

    //类中使用的路径
    //task2 是为第二代加速设计的 文件使用透明转发 http使用代理
    //系统平台使用华为欧拉 LS 版本SP1
    //20230212
    public function __construct() {
        parent::__construct();
        //{hook a_post_init}
        if(!IS_LOGIN){
            if(IS_AJAX && IS_POST){
                die($this->json(array('error'=>false,'info'=>'请登录后再操作')));
            }
            else{
                header("location: ". HYBBS_URLA('user','login'));
                die;
            }
        }
    }
    public function fileView(){
        //文件传输加速拓扑
        // $task = S('fhl_ctask')->query('select * from hy_fhl_stask')->fetchALL();
        //$this->v('task',$task);
        $this->view = 'FHL';
        $this->display('fileTask');

    }
    public function webView(){
        //文件传输加速拓扑
        // $task = S('fhl_ctask')->query('select * from hy_fhl_stask')->fetchALL();
        //$this->v('task',$task);
        $this->view = 'FHL';
        $this->display('webTask');

    }
    //前台获取ip列表
    public function getIps(){
        //$op = X("get.op","active");
        //$this->json(M("Sysinfo")->getIps($op));
        $res = [];
        foreach(M("Sysinfo")->getIps() as $k=>$v){
            if((strpos($v["ethname"],'en')===0||strpos($v["ethname"],'eth')===0)&&$v["ip"]!="192.168.1.1"){
                array_push($res,$v);
            }
        }
        $this->json(["state"=>true,"data"=>$res]);
    }
    //获拓扑数据
    public function getTopoData(){
        $op = X("get.op","file");
        //$this->json(M("Sysinfo")->getIps($op));
        if($op == "file"){
            $nodes = S("fhl_nodes")->query('select * from hy_fhl_nodes WHERE service = \'file\'')->fetchALL();
            $links = S("fhl_links")->query('select * from hy_fhl_links WHERE service = \'file\'')->fetchALL();
        }
        $this->json(["state"=>true,"data"=>[
            'nodes'=>$nodes,
            'links'=>$links
        ]]);
    }
    //增加任务 这里文件或代理都在这里增加
    public function addTask(){
        $linkName = X("post.linkName","任务名称");
        $direction = X("post.direction");
        $speed = intval(X("post.speed",0));//0不限速
        $clientIp = X("post.clientIp","0.0.0.0");
        $clientPort = intval(X("post.clientPort"));
        $localSpeederIpToC = X("post.localSpeederIpToC","0.0.0.0");
        $localSpeederInPortToC = intval(X("post.localSpeederInPortToC"));
        $localSpeederIpToS = X("post.localSpeederIpToS","0.0.0.0");
        $localSpeederInPortToS = intval(X("post.localSpeederInPortToS"));
        $remoteSpeederIp = X("post.remoteSpeederIp","0.0.0.0");
        $remoteSpeederPort = intval(X("post.remoteSpeederPort"));
        $service = X("post.service");
        $rootid = S('fhl_nodes')->query('select nid from hy_fhl_nodes where tkid = 0 and service = \''.$service.'\'')->fetchALL();

        if($speed>10000){
            $this->json([
                'state'=>false,
                'info'=>"限速值不能超过10000"
            ]);
        }
        if(count($rootid)!=1){
            $this->json([
                'state'=>false,
                'info'=>"service错误 没有找到唯一根节点"
            ]);
        }else{
            $rootid = $rootid[0]["nid"];
        }
        //判断ip合法性
        if(!filter_var($clientIp,FILTER_VALIDATE_IP))
        {
            $this->json([
                'state'=>false,
                'info'=>"clientIp错误"
            ]);
        }
        if(!filter_var($localSpeederIpToC,FILTER_VALIDATE_IP))
        {
            $this->json([
                'state'=>false,
                'info'=>"localSpeederIpToC错误"
            ]);
        }
        if(!filter_var($localSpeederIpToS,FILTER_VALIDATE_IP))
        {
            $this->json([
                'state'=>false,
                'info'=>"localSpeederIpToS错误"
            ]);
        }
        if(!filter_var($remoteSpeederIp,FILTER_VALIDATE_IP))
        {
            $this->json([
                'state'=>false,
                'info'=>"remoteSpeederIp错误"
            ]);
        }
        switch ($service) {
            case 'file'://文件透明转发模式
                $tkid = S("fhl_task");
                $tkid ->insert([
                    'tkname'=>$linkName,
                    'direction'=>$direction,
                    'service'=>$service,
                    'direction'=>$direction
                ]);
                $tkid = $tkid->id();
                //增加节点实体
                $localClientId = S("fhl_nodes");
                $localClientId ->insert([
                    'tkid'=>$tkid,
                    'service'=>$service,
                    'type'=>"localclient",
                    'img'=>"pc.png",
                    'name'=>"客户端",
                    'x'=>1,
                    'y'=>120
                ]);
                $localClientId =$localClientId->id();
                $remoteSpeederId=S("fhl_nodes");
                $remoteSpeederId->insert([
                    'tkid'=>$tkid,
                    'service'=>$service,
                    'type'=>"remotespeeder",
                    'img'=>"speeder.png",
                    'name'=>"远端加速器",
                    'x'=>100,
                    'y'=>120
                ]);
                $remoteSpeederId = $remoteSpeederId->id();
                S("fhl_links")->insert([
                    [
                        //远端加速节点<-->本地加速节点间
                        'tkid'=>$tkid,
                        'speed'=>$speed,
                        'service'=>$service,
                        'direction'=>$direction,
                        'tport'=>$direction=="recive"?$localSpeederInPortToS:$remoteSpeederPort,
                        'sport'=>'0',
                        'tip'=>$direction=="recive"?$localSpeederIpToS:$remoteSpeederIp,
                        'sip'=>$direction=="recive"?$remoteSpeederIp:$localSpeederIpToS,
                        'name'=>$linkName,
                        'target'=>$direction=="recive"?$rootid:$remoteSpeederId,
                        'source'=>$direction=="recive"?$remoteSpeederId:$rootid,
                    ],[
                        //本地加速节点<-->本地client
                        'tkid'=>$tkid,
                        'speed'=>$speed,
                        'service'=>$service,
                        'direction'=>$direction,
                        'tport'=>$direction=="recive"?$clientPort:$localSpeederInPortToC,
                        'sport'=>'0',
                        'tip'=>$direction=="recive"?$clientIp:$localSpeederIpToC,
                        'sip'=>$direction=="recive"?$localSpeederIpToC:$clientIp,
                        'name'=>$linkName,
                        'target'=>$direction=="recive"?$localClientId:$rootid,
                        'source'=>$direction=="recive"?$rootid:$localClientId,
                    ]
                ]);




                break;
            case 'http':
                break;
        }
        $this->json([
            "state"=>true,
        ]);
    }
    public function editTask(){


    }
    //控制任务启动停止
    public function controlTask(){
        $op = X("post.op");
        $tkid = intval(X("post.tkid"));
        $service = X("post.service");
        $tkinfo = S('fhl_links')->query('select * from hy_fhl_links l join hy_fhl_nodes n
								on l.source = n.nid  and l.tkid='.$tkid.' ORDER BY n.type ')->fetchALL();
        //必须是两条任务才能控制
        if(count($tkinfo)!=2){
            //如果获取的的link不是两条 则返回
            $this->json(['state'=>false,'info'=>"tkid错误",'data'=>$tkinfo]);
        }
        S("fhl_links")->query('
          INSERT INTO eventlog (content, cdt) VALUES (\'链路['.$tkinfo[0]['name'].']相关任务-'.$op.'\', \'2023-02-23 13:49:03\')
        ');
        //这里已经可以保证 tkid是正确的
        switch ($service) {
            case 'file'://文件透明转发模式
                $SnatCmd =" POSTROUTING -s ".$tkinfo[1]["sip"]." -d ".$tkinfo[0]["tip"]."  -p udp --dport ".$tkinfo[0]["tport"]." -j SNAT --to-source ".$tkinfo[0]["sip"];
                $DnatCmd =" PREROUTING -d ".$tkinfo[1]["tip"]." -s ".$tkinfo[1]["sip"]." -p udp --dport ".$tkinfo[1]["tport"]." -j DNAT --to-destination ".$tkinfo[0]["tip"].":".$tkinfo[0]["tport"];
                $acceptSpeed = "FORWARD -m limit -s ".$tkinfo[1]["sip"]." -p udp --dport ".$tkinfo[0]["tport"]."   --limit ".$tkinfo[1]["speed"]."/s --limit-burst 100 -j ACCEPT";
                $dropSpeed = " FORWARD -s ".$tkinfo[1]["sip"]." -p udp --dport ".$tkinfo[0]["tport"]." -j DROP";
                if($op=="start"){
                    //需要先检查任务是否存在
                    //$this->json($acceptSpeed);

                    M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -D".$SnatCmd);
                    M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -D".$DnatCmd);
                    $rsS=M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -A".$SnatCmd);
                    $rsD=M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -A".$DnatCmd);
                    if($tkinfo[1]["speed"]!=0){
                        M("Sysinfo")->execCmd("/usr/sbin/iptables -A ".$acceptSpeed);
                        M("Sysinfo")->execCmd("/usr/sbin/iptables -A ".$dropSpeed);
                    }
                    M("Sysinfo")->execCmd("/usr/sbin/conntrack -D");
                    if($rsD!=""||$rsS!=""){
                        $this->json([
                            "state"=>false,
                            "info"=>"任务启动失败，请检查端口是否重复，或重启设备"
                        ]);
                    }else{
                        //修改任务表
                        S("fhl_task")->update([
                            "status"=>1
                        ],[
                            "tkid"=>$tkid
                        ]);
                        $this->json([
                            "state"=>true,
                            "info"=>"任务启动成功",
                            "con"=>$acceptSpeed
                        ]);
                    }
                }elseif($op == "del"){
                    //删除任务
                    //数据库删除
                    M("Sysinfo")->execCmd("/usr/sbin/conntrack -D");
                    M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -D".$SnatCmd);
                    M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -D".$DnatCmd);
                    if($tkinfo[1]["speed"]!=0){
                        M("Sysinfo")->execCmd("/usr/sbin/iptables -D ".$acceptSpeed);
                        M("Sysinfo")->execCmd("/usr/sbin/iptables -D ".$dropSpeed);
                    }
                    M("Sysinfo")->execCmd("/usr/sbin/conntrack -D");
                    S('fhl_nodes')->delete([
                        'tkid'=>$tkid
                    ]);
                    S('fhl_links')->delete([
                        'tkid'=>$tkid
                    ]);
                    S('fhl_task')->delete([
                        'tkid'=>$tkid
                    ]);

                }elseif($op == "stop"){
                    M("Sysinfo")->execCmd("/usr/sbin/conntrack -D");
                    M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -D".$SnatCmd);
                    M("Sysinfo")->execCmd("/usr/sbin/iptables -t nat -D".$DnatCmd);
                    if($tkinfo[1]["speed"]!=0){
                        M("Sysinfo")->execCmd("/usr/sbin/iptables -D ".$acceptSpeed);
                        M("Sysinfo")->execCmd("/usr/sbin/iptables -D ".$dropSpeed);
                    }
                    M("Sysinfo")->execCmd("/usr/sbin/conntrack -D");
                    S("fhl_task")->update([
                        "status"=>0
                    ],[
                        "tkid"=>$tkid
                    ]);
                }

                break;
            case 'http':
                break;
        }
        $this->json([
            "state"=>true,
        ]);
    }

    //pingtask涉及到的所有ip
    //将所有涉及的ip ping一遍
    public function taskPing(){
        $tkid = intval(X("post.tkid"));
        $tkinfo = S('fhl_links')->query("select * from hy_fhl_links l join hy_fhl_task t
								on l.tkid = t.tkid and t.tkid=".$tkid)->fetchALL();
        if(count($tkinfo)!=2){
            //如果获取的的link不是两条 则返回
            $this->json(['state'=>false,'info'=>"tkid错误",'data'=>$tkinfo]);
        }
        $ips = "";
        $ips.=$tkinfo[0]["sip"]=="0.0.0.0"?"":$tkinfo[0]["sip"]." ";
        $ips.=$tkinfo[0]["tip"]=="0.0.0.0"?"":$tkinfo[0]["tip"]." ";
        $ips.=$tkinfo[1]["sip"]=="0.0.0.0"?"":$tkinfo[1]["sip"]." ";
        $ips.=$tkinfo[1]["tip"]=="0.0.0.0"?"":$tkinfo[1]["tip"]." ";
        $res = M("Sysinfo")->ping($ips);

        $this->json([
            'state'=>true,
            'info'=>$res
        ]);
    }


    //一键自动测试
    public function FHLtaskPing(){
        $tkid = intval(X("post.tkid"));
        $tkinfo = S('fhl_links')->query("select * from hy_fhl_links l join hy_fhl_task t
								on l.tkid = t.tkid and t.tkid=".$tkid)->fetchALL();
        if(count($tkinfo)!=2){
            //如果获取的的link不是两条 则返回
            $this->json(['state'=>false,'info'=>"tkid错误",'data'=>$tkinfo]);
        }
        $res = [];//返回信息用的数组
        $link_ips = ['ip1'=>'','ip2'=>'','port2'=>'','ip3'=>'','port3'=>''];
        if($tkinfo[0]['source']==0){
            $link_ips['ip2']=$tkinfo[0]['sip'];
            $link_ips['ip3']=$tkinfo[0]['tip'];
            $link_ips['port3']=$tkinfo[0]['tport'];
            $link_ips['ip1']=$tkinfo[1]['sip'];
            $link_ips['port2']=$tkinfo[1]['tport'];
        }else{
            $link_ips['ip2']=$tkinfo[0]['tip'];
            $link_ips['port2']=$tkinfo[0]['tport'];
            $link_ips['ip3']=$tkinfo[1]['tip'];
            $link_ips['port3']=$tkinfo[1]['tport'];
            $link_ips['ip1']=$tkinfo[0]['sip'];
        }
        if($tkinfo[0]['direction']=='send'){
            array_push($res,"当前加速链路将客户端数据【发送】到远端加速器");
            array_push($res,"客户IP【".$link_ips['ip1'].'】将数据发送到');
            array_push($res,"本地加速器【".$link_ips['ip2'].':'.$link_ips['port2'].'】');
            //$resping =M("Sysinfo")->execCmd("/home/wwwroot/FHL/FHLping ".$link_ips['ip2']." ".$link_ips['port2']);
            //array_push($res,$link_ips['ip2'].':'.$link_ips['port2']."加速协议连接测试结果".$resping);
            array_push($res,"打包优化后发到远端加速器【".$link_ips['ip3'].':'.$link_ips['port3'].'】');
            $resping =M("Sysinfo")->execCmd("/home/wwwroot/FHL/FHLping ".$link_ips['ip3']." ".$link_ips['port3']);
            array_push($res,$link_ips['ip3'].':'.$link_ips['port3']."加速协议连接测试结果".$resping);   
        }else{
            array_push($res,"当前加速链路【接收】远端加速器数据到本地客户端");
            array_push($res,"远端加速器IP【".$link_ips['ip1'].'】将数据打包优化发送到');
            array_push($res,"本地加速器【".$link_ips['ip2'].':'.$link_ips['port2'].'】');
            //$resping =M("Sysinfo")->execCmd("/home/wwwroot/FHL/FHLping ".$link_ips['ip2']." ".$link_ips['port2']);
            //array_push($res,$link_ips['ip2'].':'.$link_ips['port2']."加速协议连接测试结果".$resping);
            array_push($res,"打包优化后发到客户端【".$link_ips['ip3'].':'.$link_ips['port3'].'】');
            $resping =M("Sysinfo")->execCmd("/home/wwwroot/FHL/FHLping ".$link_ips['ip3']." ".$link_ips['port3']);
            array_push($res,$link_ips['ip3'].':'.$link_ips['port3']."加速协议连接测试结果".$resping);
        }


        $this->json([
            'state'=>true,
            'info'=>$res
        ]);
    }

    //针对任务的50ms延时操作
    //延时需要选择网卡 所以需要根据ip判断 所以需要知道操作类型
    public function taskDelay()
    {
        $tkid = intval(X("post.tkid"));
        $op = X("post.op");
        $service = X("post.service");
        $ips = M("Sysinfo")->getIps();
        $ethname = "";
        $cmd = "";
        switch($service) {
            case 'file'://文件透明转发模式
                $tkinfo = S('fhl_links')->query('select * from hy_fhl_links l join hy_fhl_nodes n
								on l.source = n.nid  and n.type=\'localspeeder\' and l.tkid='.$tkid )->fetchALL();
                if (count($tkinfo) != 1) {
                    //如果获取的的link不是两条 则返回
                    $this->json(['state' => false, 'info' => "tkid错误", 'data' => $tkinfo]);
                }
                foreach ($ips as $k=>$v) {
                    if($v['ip']==$tkinfo[0]['sip']){
                        $ethname = $v['ethname'];
                    }
                }
                break;

        }

        if($op=="addDelay"){
            $cmd = "/usr/sbin/tc qdisc add dev ".$ethname." root netem delay 50ms";
        }else{
            $cmd = "/usr/sbin/tc qdisc del dev ".$ethname." root netem delay 50ms";
        }
        //执行命令这是延时
        //$this->json($cmd);
        $res = M("Sysinfo")->execCmd($cmd);
        if($res !=""){
            $this->json([
                'state'=>false,
                'info'=>$res
            ]);
        }
        $this->json([
            'state'=>true,
            'info'=>$op=="addDelay"?"已添加50ms延时":"已去掉50ms延时"
        ]);

    }


}
